package com.parser;

import com.lexicalAnalyzer.*;

import java.io.IOException;
import java.util.ArrayList;

/**
 * Created with IntelliJ IDEA.
 * User: Gauti
 * Date: 26.10.2012
 * Time: 18:05
 * To change this template use File | Settings | File Templates.
 */
public class Parser extends ParserBase
{
    @Override
    protected boolean tokenCodeIn(TokenCode tc, TokenCode[] plist)
    {
        return false;
    }

    @Override
    protected void recover(TokenCode[] plist) {
        //To change body of implemented methods use File | Settings | File Templates.
    }

    @Override
    protected void getToken()
    {
        try
        {
            m_currentToken =    m_lexan.nextToken();
        }
        catch (IOException Ex)
        {
            Ex.printStackTrace();
        }
    }

    @Override
    protected Token match(TokenCode tc) // throws TokenMismatchException
    {
        if(getTokenCode().equals(tc))
        {
            getToken();
            return m_currentToken;
        }
        else
        {
            System.out.println("The token that doesnt match : " + tc.toString());
        }
        return m_currentToken;
    }

    @Override
    protected void setError(String err)
    {
        //To change body of implemented methods use File | Settings | File Templates.
    }

    @Override
    protected void parseArrayReference()
    {
        if(getTokenCode() == TokenCode.LBRACKET)
        {
            match(TokenCode.LBRACKET);

            parseExpression();

            match(TokenCode.RBRACKET);
        }

        //To change body of implemented methods use File | Settings | File Templates.
    }

    @Override
    protected SymbolTableEntry parseFactorRest(SymbolTableEntry prevEntry)
    {
        if(getTokenCode() == TokenCode.LPAREN)
        {
            match(TokenCode.LPAREN);

            parseExpressionList(prevEntry);

            match(TokenCode.RPAREN);
        }

        return null;
    }

    @Override
    protected SymbolTableEntry parseFactor()
    {
        SymbolTableEntry entry = null;

        if(getTokenCode() == TokenCode.ID)
        {
            match(TokenCode.ID);

            parseIdOrProcedureStatement(entry);

            entry = parseFactorRest(entry);
        }
        else if(getTokenCode() == TokenCode.NUMBER)
        {
            match(TokenCode.NUMBER);
        }
        else if(getTokenCode() == TokenCode.LPAREN)
        {
            match(TokenCode.LPAREN);

            entry = parseExpression();

            match(TokenCode.RPAREN);
        }
        else if(getTokenCode() == TokenCode.NOT)
        {
            match(TokenCode.NOT);
            entry = parseFactor();
        }

        return entry;



    }

    @Override
    protected SymbolTableEntry parseTermRest(SymbolTableEntry prevEntry)
    {
        SymbolTableEntry entry = null;

        if(getTokenCode() == TokenCode.MULOP)
        {
            match(TokenCode.MULOP);

            entry = parseFactor();

            entry = parseTermRest(entry);
        }

        return entry;
    }

    @Override
    protected SymbolTableEntry parseTerm()
    {
        SymbolTableEntry entry;

        entry = parseFactor();

        entry = parseTermRest(entry);

        return entry;

    }

    @Override
    protected SymbolTableEntry parseSimpleExpressionAddop(SymbolTableEntry prevEntry) {
        return null;  //To change body of implemented methods use File | Settings | File Templates.
    }

    @Override
    protected SymbolTableEntry parseSimpleExpressionRelop(SymbolTableEntry prevEntry) {
        return null;  //To change body of implemented methods use File | Settings | File Templates.
    }

    @Override
    protected void parseSign()
    {
        if(getTokenCode() == TokenCode.ADDOP)
        {
            match(TokenCode.ADDOP);
        }
    }

    protected SymbolTableEntry parseSimpleExpressionMore(SymbolTableEntry prevEntry)
    {
        if(getTokenCode() == TokenCode.ADDOP)
        {
            match(TokenCode.ADDOP);
            prevEntry = parseTerm();
            prevEntry = parseSimpleExpressionMore(prevEntry);
        }

        return prevEntry;
    }

    @Override
    protected SymbolTableEntry parseSimpleExpression()
    {
        SymbolTableEntry entry = null;

        entry = parseTerm();
        entry = parseSimpleExpressionMore(entry);
        parseSign();

        return entry;
    }

    @Override
    protected void parseExpressionListMore(ArrayList<SymbolTableEntry> eList)
    {
        SymbolTableEntry entry;
        if(getTokenCode() == TokenCode.COMMA);
        {
            match(TokenCode.COMMA);

            entry = parseExpression();

            parseExpressionListMore(eList);
        }
    }

    @Override
    protected void parseExpressionList(SymbolTableEntry prevEntry)
    {
        ArrayList<SymbolTableEntry> list = new ArrayList<SymbolTableEntry>();
        parseExpression();

        parseExpressionListMore(list);
    }

    protected SymbolTableEntry parseExpressionMore(SymbolTableEntry preEntry)
    {
        if(getTokenCode() == TokenCode.RELOP)
        {
            match(TokenCode.RELOP);
        }

        preEntry = parseSimpleExpression();

       return preEntry;
    }

    @Override
    protected SymbolTableEntry parseExpression()
    {
        SymbolTableEntry entry = null;

        parseSimpleExpression();

        parseExpressionMore(entry);

        return entry;
    }

    @Override
    protected void parseIdOrProcedureStatement(SymbolTableEntry prevEntry)
    {
        if(getTokenCode() == TokenCode.ID)
        {
            match(TokenCode.ID);

            parseIdOrProcedureStatement(prevEntry);

        }
        else if(getTokenCode() == TokenCode.LPAREN)
        {
            match(TokenCode.LPAREN);

            parseExpressionList(prevEntry);

            match(TokenCode.RPAREN);

            //parseIdOrProcedureStatement(prevEntry);
        }
        else if(getTokenCode() == TokenCode.LBRACKET)
        {
            match(TokenCode.LBRACKET);

            parseExpression();

            match(TokenCode.RBRACKET);

            parseIdOrProcedureStatement(prevEntry);
        }
        else if (getTokenCode() == TokenCode.ASSIGNOP)
        {
            match(TokenCode.ASSIGNOP);
            parseExpression();
        }
    }

    @Override
    protected void parseWhileStatement()
    {
        if(getTokenCode() == TokenCode.WHILE)
        {
           match(TokenCode.WHILE);
           parseExpression();
           match(TokenCode.DO);
           parseStatement();
        }
    }

    @Override
    protected void parseIfStatement()
    {
        match(TokenCode.IF);
        parseExpression();
        match(TokenCode.THEN);
        parseStatement();
        match(TokenCode.ELSE);
        parseStatement();


    }

    @Override
    protected void parseStatement()
    {
        SymbolTableEntry entry = null;

        if(getTokenCode() == TokenCode.ID)
        {
            match(TokenCode.ID);
            parseIdOrProcedureStatement(entry);
        }

        else if(getTokenCode() == TokenCode.IF)
        {
            match(TokenCode.IF);
            parseIfStatement();
        }
        else if(getTokenCode() == TokenCode.WHILE)
        {
            parseWhileStatement();
        }
        else
        {
            parseCompoundStatement();
        }
    }

    @Override
    protected void parseStatementListMore()
    {
        if(getTokenCode() == TokenCode.SEMICOL)
        {
            match(TokenCode.SEMICOL);

            parseStatement();

            parseStatementListMore();
        }
    }

    @Override
    protected void parseStatementList()
    {

        parseStatement();
        parseStatementListMore();

    }

    @Override
    protected void parseOptionalStatements()
    {
        parseStatementList();
    }

    @Override
    protected void parseCompoundStatement()
    {
        if(getTokenCode() == TokenCode.BEGIN)
        {
            match(TokenCode.BEGIN);

            parseOptionalStatements();

            match(TokenCode.END);
        }

    }

    @Override
    protected void parseStandardType()
    {
        if(getTokenCode() == TokenCode.INTEGER)
        {
            match(TokenCode.INTEGER);
        }
        else if (getTokenCode() == TokenCode.REAL)
        {
            match(TokenCode.REAL);
        }
    }

    @Override
    protected void parseType()
    {
        if(getTokenCode() == TokenCode.INTEGER || getTokenCode() == TokenCode.REAL)
        {
            parseStandardType();
        }

        else if (getTokenCode() == TokenCode.ARRAY)
        {
            match(TokenCode.ARRAY);
            match(TokenCode.LBRACKET);
            match(TokenCode.NUMBER);
            match(TokenCode.DOTDOT);
            match(TokenCode.NUMBER);
            match(TokenCode.RBRACKET);
            match(TokenCode.OF);
            parseStandardType();
        }
    }

    @Override
    protected void parseIdentifierListAndType(boolean subProgramHead)
    {
        ArrayList<SymbolTableEntry> entryArrayList = new ArrayList<SymbolTableEntry>();
        parseIdentifierList(entryArrayList);

        if(getTokenCode() == TokenCode.COLON)
        {
            match(TokenCode.COLON);
        }
        parseType(); //

    }

    @Override
    protected void parseIdentifierListMore(ArrayList<SymbolTableEntry> eList)
    {
        if(getTokenCode() == TokenCode.COMMA)
        {
            // it always calls itself if there are more tokens
            match(TokenCode.COMMA);
            match(TokenCode.ID);
            parseIdentifierListMore(eList);
        }
        return;
    }

    @Override
    protected void parseIdentifierList(ArrayList<SymbolTableEntry> eList)
    {
        if(getTokenCode() == TokenCode.ID)
        {
            match(TokenCode.ID);
            parseIdentifierListMore(eList);
        }
    }

    @Override
    protected void parseParameterListMore()
    {
        if(getTokenCode() == TokenCode.SEMICOL)
        {
            match(TokenCode.SEMICOL);

            parseIdentifierListAndType(false);

            parseParameterListMore();

        }
    }

    @Override
    protected void parseParameterList()
    {
        parseIdentifierListAndType(false);

        parseParameterListMore();

    }

    @Override
    protected void parseArguments()
    {
        if(getTokenCode() == TokenCode.LPAREN)
        {
            match(TokenCode.LPAREN);
            parseParameterList();

            match(TokenCode.RPAREN);

        }
    }

    @Override
    protected void parseSubprogramHead()
    {
        if(getTokenCode() == TokenCode.FUNCTION)
        {
            match(TokenCode.FUNCTION);
            match(TokenCode.ID);
            parseArguments();
            match(TokenCode.COLON);
            parseStandardType();
            match(TokenCode.SEMICOL);
        }
        else if (getTokenCode() == TokenCode.PROCEDURE)
        {
            match(TokenCode.PROCEDURE);
            match(TokenCode.ID);
            parseArguments();
        }
    }

    @Override
    protected void parseSubprogramDeclarations()
    {
        if(getTokenCode() == TokenCode.PROCEDURE || getTokenCode() == TokenCode.FUNCTION)
        {
            parseSubprogramDeclaration();

            if(getTokenCode() == TokenCode.PROCEDURE)
            {
                match(TokenCode.PROCEDURE);
            }
            else if(getTokenCode() == TokenCode.FUNCTION)
            {
                match(TokenCode.FUNCTION);
            }

            if(getTokenCode() == TokenCode.SEMICOL)
            {
                match(TokenCode.SEMICOL);

                parseSubprogramDeclarations();
            }
        }
    }

    @Override
    protected void parseSubprogramDeclaration()
    {
        parseSubprogramHead();
        parseDeclarations(true);
        parseCompoundStatement();
    }

    @Override
    protected void parseDeclarations(boolean subProgramHead)
    {
        if(getTokenCode() == TokenCode.VAR)
        {
            match(TokenCode.VAR);


        parseIdentifierListAndType(subProgramHead);
        match(TokenCode.SEMICOL);
        parseDeclarations(subProgramHead);     // error i þessari linu alltaf  , subProgramHead var paramter

        }
    }

    @Override
    protected SymbolTableEntry parseProgramDefinition()
    {
        match(TokenCode.PROGRAM);
        match(TokenCode.ID);
        match(TokenCode.LPAREN);
        ArrayList<SymbolTableEntry> entryList = new ArrayList<SymbolTableEntry>();

        parseIdentifierList(entryList);
        match(TokenCode.RPAREN);
        return null;
    }

    @Override
    protected void parseProgram()
    {
        parseProgramDefinition();
        if(getTokenCode() == TokenCode.SEMICOL)
        {

            match(TokenCode.SEMICOL);
            parseDeclarations(false);
            parseSubprogramDeclarations();
            parseCompoundStatement();
            if(getTokenCode() == TokenCode.DOT)
            {
                    match(TokenCode.DOT);
            }
    }
 }

    @Override
    protected CodeOperator opToCode(OperatorType op)
    {
        return null;  //To change body of implemented methods use File | Settings | File Templates.
    }

    @Override
    protected SymbolTableEntry newTemp()
    {
        return null;  //To change body of implemented methods use File | Settings | File Templates.
    }

    @Override
    protected SymbolTableEntry newLabel()
    {
        return null;  //To change body of implemented methods use File | Settings | File Templates.
    }

    @Override
    public void parse()
    {
        getToken();
        parseProgram();
    }

    @Override
    public ISymbolTable getSymbolTable()
    {
        return m_symTab;  //To change body of implemented methods use File | Settings | File Templates.
    }
    public void setScanner(Scanner scanner)
    {
        m_lexan = scanner;
    }
}
